/*
 *  Brno University of Technology
 *
 *  Copyright (C) 2009-2010 by Brno University of Technology and the contributors
 *
 *  Complete list of developers available at our web site:
 *
 *       http://spl.utko.feec.vutbr.cz
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
 */
package cz.vutbr.feec.utko.ef.grammar;

import java.io.Serializable;

import cz.vutbr.feec.utko.ef.individuals.ActionTree;
import cz.vutbr.feec.utko.ef.individuals.DummyAction;

/**
 * The Class Rule defines rules contained be grammar.
 */
public class Rule implements Serializable {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1776276323649724481L;
	
	/** The child tokens. */
	private String[] childTokens;
	
	/** The action. */
	private ActionTree action;

	/** The parent token. */
	private String parentToken;

	/** The max production length. */
	private int maxProductionLength = Integer.MAX_VALUE;

	/**
	 * Instantiates a new rule.
	 * 
	 * @param action
	 *            the action
	 * @param childTokens
	 *            the child tokens
	 */
	public Rule(ActionTree action, String... childTokens) {
		this.childTokens = childTokens;
		this.action = action;
		if (action != null) {
			action.setRule(this);
		}
		if (isTerminal()) {
			if (action == null) {
				throw new RuntimeException("A terminal node must "
						+ "have specified an action.");
			} else if(!action.isInputParameter()){
				// if action has not overridden the initialize method, it will
				// throw an exception.
				action.initialize();
			}
		}
	}

	/**
	 * Instantiates a new rule.
	 * 
	 * @param successorTokens
	 *            the successor tokens
	 */
	public Rule(String successorTokens) {
		this(new DummyAction(), successorTokens);
	}

	/**
	 * Gets the action.
	 * 
	 * @return the action
	 */
	public ActionTree getAction() {
		return action;
	}

	/**
	 * Gets the from token.
	 * 
	 * @return the from token
	 */
	public String getFromToken() {
		return parentToken;
	}

	/**
	 * Gets the child tokens.
	 * 
	 * @return the child tokens
	 */
	public String[] getChildTokens() {
		return childTokens;
	}

	/**
	 * Gets maximal production lengths of all its successors.
	 * 
	 * @return production length
	 */
	public int getProductionLength() {
		return maxProductionLength;
	}

	/**
	 * Gets the result.
	 * 
	 * @return the result
	 */
	public Object getResult() {
		return null;
	}

	/**
	 * Checks for infinite production length.
	 * 
	 * @return true, if successful
	 */
	public boolean hasInfiniteProductionLength() {
		return maxProductionLength == Integer.MAX_VALUE;
	}

	/**
	 * Checks if is terminal.
	 * 
	 * @return true, if is terminal
	 */
	public boolean isTerminal() {
		return childTokens.length == 0;
	}

	/**
	 * Sets the action.
	 * 
	 * @param action
	 *            the new action
	 */
	protected void setAction(ActionTree action) {
		this.action = action;
	}

	/**
	 * Sets the child tokens.
	 * 
	 * @param childTokens
	 *            the new child tokens
	 */
	protected void setChildTokens(String[] childTokens) {
		this.childTokens = childTokens;
	}

	/**
	 * Sets the parent token.
	 * 
	 * @param parentToken
	 *            the new parent token
	 */
	public void setParentToken(String parentToken) {
		this.parentToken = parentToken;
	}
	
	/**
	 * Sets the production length.
	 * 
	 * @param maxProductionLength
	 *            the new production length
	 */
	protected void setProductionLength(int maxProductionLength) {
		this.maxProductionLength = maxProductionLength;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		String res = " ";
		for (String t : childTokens) {
			res += t + ",";
		}
		return "" + parentToken + "->" + res;
	}
}
